#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <gmssl/sm2.h>
#include <gmssl/error.h>
#include <gmssl/pem.h>

// 读取文件内容
int read_file(const char *filename, uint8_t **content, size_t *len) {
    FILE *file = fopen(filename, "rb");
    if (!file) {
        printf("错误: 无法打开文件 %s\n", filename);
        return 0;
    }
    
    fseek(file, 0, SEEK_END);
    *len = ftell(file);
    fseek(file, 0, SEEK_SET);
    
    *content = (uint8_t *)malloc(*len + 1);
    if (!*content) {
        printf("错误: 内存分配失败\n");
        fclose(file);
        return 0;
    }
    
    size_t read_len = fread(*content, 1, *len, file);
    fclose(file);
    
    if (read_len != *len) {
        printf("错误: 读取文件不完整\n");
        free(*content);
        return 0;
    }
    
    (*content)[*len] = '\0';
    return 1;
}

// 写入文件内容
int write_file(const char *filename, const uint8_t *content, size_t len) {
    FILE *file = fopen(filename, "wb");
    if (!file) {
        printf("错误: 无法创建文件 %s\n", filename);
        return 0;
    }
    
    size_t write_len = fwrite(content, 1, len, file);
    fclose(file);
    
    if (write_len != len) {
        printf("错误: 写入文件不完整\n");
        return 0;
    }
    
    return 1;
}

// 从PEM文件读取公钥
int load_public_key(const char *filename, SM2_KEY *key) {
    FILE *file = fopen(filename, "r");
    if (!file) {
        printf("错误: 无法打开公钥文件 %s\n", filename);
        return 0;
    }
    
    if (sm2_public_key_info_from_pem(key, file) != 1) {
        printf("错误: 读取公钥失败\n");
        fclose(file);
        return 0;
    }
    
    fclose(file);
    return 1;
}

// 从PEM文件读取私钥（带密码）
int load_private_key(const char *filename, const char *password, SM2_KEY *key) {
    FILE *file = fopen(filename, "r");
    if (!file) {
        printf("错误: 无法打开私钥文件 %s\n", filename);
        return 0;
    }
    
    if (sm2_private_key_info_decrypt_from_pem(key, password, file) != 1) {
        printf("错误: 读取私钥失败，请检查密码\n");
        fclose(file);
        return 0;
    }
    
    fclose(file);
    return 1;
}

// 将二进制数据转换为十六进制字符串
void print_hex(const uint8_t *data, size_t len) {
    for (size_t i = 0; i < len; i++) {
        printf("%02X", data[i]);
        if (i < len - 1) {
            printf(" ");
        }
    }
    printf("\n");
}

int main() {
    printf("=== SM2加密解密 ===\n\n");
    
    uint8_t *plaintext = NULL;
    size_t plaintext_len = 0;
    uint8_t ciphertext[1024];
    size_t ciphertext_len = 0;
    uint8_t decrypted[1024];
    size_t decrypted_len = 0;
    
    SM2_KEY public_key;
    SM2_KEY private_key;
    
    const char *password = "1318"; 
    
    // 1. 读取原始文件
    printf("1. 读取原始文件 sn.txt\n");
    if (!read_file("sn.txt", &plaintext, &plaintext_len)) {
        return 1;
    }
    
    printf("文件内容(%zu字节):\n", plaintext_len);
    printf("%.*s\n\n", (int)plaintext_len, plaintext);
    
    // 2. 读取公钥
    printf("2. 读取公钥\n");
    if (!load_public_key("sm2pub.pem", &public_key)) {
        free(plaintext);
        return 1;
    }
    printf("公钥读取成功\n");
    
    // 3. 加密文件
    printf("3. 加密文件\n");
    if (sm2_encrypt(&public_key, plaintext, plaintext_len, 
                    ciphertext, &ciphertext_len) != 1) {
        printf("错误: 加密失败\n");
        free(plaintext);
        return 1;
    }
    
    if (!write_file("sn_encrypted.bin", ciphertext, ciphertext_len)) {
        free(plaintext);
        return 1;
    }
    printf("加密成功，密文长度: %zu 字节\n", ciphertext_len);
    
    // 打印密文的十六进制表示
    printf("密文内容(十六进制):\n");
    print_hex(ciphertext, ciphertext_len);
    printf("\n");
    
    // 4. 读取私钥（使用密码）
    printf("4. 读取私钥（密码: %s）\n", password);
    if (!load_private_key("sm2.pem", password, &private_key)) {
        free(plaintext);
        return 1;
    }
    printf("私钥读取成功\n");
    
    // 5. 解密文件
    printf("5. 解密文件\n");
    if (sm2_decrypt(&private_key, ciphertext, ciphertext_len, 
                    decrypted, &decrypted_len) != 1) {
        printf("错误: 解密失败\n");
        free(plaintext);
        return 1;
    }
    
    if (!write_file("sn_decrypted.txt", decrypted, decrypted_len)) {
        free(plaintext);
        return 1;
    }
    printf("解密成功，明文长度: %zu 字节\n", decrypted_len);
    
    // 6. 验证结果
    printf("6. 验证加解密结果\n");
    printf("解密后内容:\n");
    printf("%.*s\n", (int)decrypted_len, decrypted);
    
    if (plaintext_len == decrypted_len && 
        memcmp(plaintext, decrypted, plaintext_len) == 0) {
        printf("加解密验证成功！\n");
    } else {
        printf("加解密验证失败\n");
    }
    
    free(plaintext);
    return 0;
}




